package com.geega.geetest.service;

import cn.hutool.core.util.StrUtil;
import com.geega.geetest.core.PageInfo;
import com.geega.geetest.core.QueryCondition;
import com.geega.geetest.dao.BaseDao;
import com.google.common.collect.Lists;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.util.List;
import java.util.stream.Collectors;

public class BaseService<T, ID> {

    protected BaseDao<T, ID> baseDao;

    public T save(T entity) {
        return baseDao.save(entity);
    }

    public void delete(T entity) {
        baseDao.delete(entity);
    }

    public void deleteById(ID id) {
        baseDao.deleteById(id);
    }

    public void deleteAll() {
        baseDao.deleteAll();
    }

    public T findOne(T entity) {
        return baseDao.findOne(Example.of(entity)).orElse(null);
    }

    public T findById(ID id) {
        return baseDao.getById(id);
    }

    public List<T> findAll() {
        return baseDao.findAll();
    }

    public PageInfo<T> findPage(QueryCondition condition) {
        // 排序
        Sort sort = Sort.by(condition.getOrderMap().entrySet().stream().map(entry -> new Sort.Order(Sort.Direction.fromString(entry.getValue()), entry.getKey())).collect(Collectors.toList()));
        // 分页
        Pageable pageable = PageRequest.of(condition.getPageNum() - 1, condition.getPageSize(), sort);
        // 动态查询
        Specification<T> specification = (root, query, cb) -> {
            List<Predicate> predicates = Lists.newArrayList();
            condition.getWhereList().forEach(attr -> {
                switch (attr.getOpt()) {
                    case "LIKE":
                        predicates.add(cb.like(root.get(attr.getKey()), "%" + attr.getVal() + "%"));
                        break;
                    case "GT":
                        predicates.add(cb.greaterThan(root.get(attr.getKey()), attr.getVal()));
                        break;
                    case "LT":
                        predicates.add(cb.lessThan(root.get(attr.getKey()), attr.getVal()));
                        break;
                    case "GTE":
                        predicates.add(cb.greaterThanOrEqualTo(root.get(attr.getKey()), attr.getVal()));
                        break;
                    case "LTE":
                        predicates.add(cb.lessThanOrEqualTo(root.get(attr.getKey()), attr.getVal()));
                        break;
                    case "IN":
                        CriteriaBuilder.In<Object> in = cb.in(root.get(attr.getKey()));
                        StrUtil.split(attr.getVal(), ",").forEach(in::value);
                        predicates.add(in);
                        break;
                    default:
                        predicates.add(cb.equal(root.get(attr.getKey()), attr.getVal()));
                }
            });
            if (!predicates.isEmpty()) {
                return cb.and(predicates.toArray(new Predicate[0]));
            }
            return cb.conjunction();
        };
        Page<T> page = baseDao.findAll(specification, pageable);
        return new PageInfo<>(page);
    }

}
